﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.ComponentModel;
using System.Reflection;
using System.Windows.Forms;

namespace LowLevelGraphics.Types.Interval
{
    /// <summary>
    /// The boundaries are momentarily included (>= ...)
    /// If they should be excluded use ONLY greater or smaller sign
    /// </summary>
    [DebuggerDisplay("[{m_nMin}, {m_nMax}]")]
    [TypeConverter(typeof(IntervalConverter<int, IntInterval>))]
    public class IntInterval : IComparable<IntInterval>, ICloneable, ICustomTypeDescriptor
    {
        protected int m_nMin = 0;
        protected int m_nMax = 0;

        /// <summary>
        /// Default Constructor
        /// </summary>
        public IntInterval()
        {
        }

        /// <summary>
        /// specify max and min bounds of IntInterval
        /// </summary>
        /// <param name="_dMin"></param>
        /// <param name="_nMax"></param>
        public IntInterval(int _dMin, int _nMax)
        {
            m_nMin = _dMin;
            m_nMax = _nMax;
        }

        /// <summary>
        /// Max value of this interval
        /// </summary>
        public int Max
        {
            get { return m_nMax; }
            set { m_nMax = value; }
        }

        /// <summary>
        /// Min value of this interval
        /// </summary>
        public int Min
        {
            get { return m_nMin; }
            set { m_nMin = value; }
        }

        /// <summary>
        /// Returns true, if the value is inside given interval
        /// </summary>
        /// <param name="_dValue"></param>
        /// <returns></returns>
        public bool Contains(int _dValue)
        {
            return _dValue >= m_nMin && _dValue <= m_nMax;
        }

        /// <summary>
        /// Check if the current interval completely contains given interval
        /// </summary>
        /// <param name="_doubleInterval"></param>
        /// <returns></returns>
        public bool Contains(IntInterval _doubleInterval)
        {
            return m_nMin <= _doubleInterval.m_nMin && m_nMax >= _doubleInterval.m_nMax;
        }

        /// <summary>
        /// This will check if an interval is overlapping, i.e. concrete:
        /// True if one of the given boundaries is contained inside the interval.
        /// The other boundary has to be outside the interval.
        /// </summary>
        /// <param name="_doubleInterval"></param>
        /// <returns></returns>
        public bool Intersects(IntInterval _doubleInterval)
        {
            return
                (Contains(_doubleInterval.m_nMax) && !Contains(_doubleInterval.m_nMin))
                || (Contains(_doubleInterval.m_nMin) && !Contains(_doubleInterval.m_nMax))
                ;
        }

        /// <summary>
        /// This returns the size of the interval.
        /// Also negative sizes are allowed to show the direction.
        /// Use Abs(Size) if direction is unimportant
        /// </summary>
        public double Size
        {
            get { return m_nMax - m_nMin; }
        }

        #region IComparable<DoubleInterval> Members

        /// <summary>
        /// An interval is bigger if its size is bigger
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public int CompareTo(IntInterval other)
        {
            return this.Size.CompareTo(other.Size);
        }

        #endregion

        /// <summary>
        /// Get interval as string in notation e.g. [0,1]
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return string.Format("[{0},{1}]", m_nMin, m_nMax);
        }

        #region ICloneable Members

        /// <summary>
        /// Use this to clone the interval
        /// </summary>
        /// <returns></returns>
        public object Clone()
        {
            return new IntInterval(this.m_nMin, this.m_nMax);
        }

        #endregion

        #region ICustomTypeDescriptor Members

        public AttributeCollection GetAttributes()
        {
            return null;
        }

        public string GetClassName()
        {
            return TypeDescriptor.GetClassName(this, true);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public string GetComponentName()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public TypeConverter GetConverter()
        {
            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public EventDescriptor GetDefaultEvent()
        {
            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public PropertyDescriptor GetDefaultProperty()
        {
            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="editorBaseType"></param>
        /// <returns></returns>
        public object GetEditor(Type editorBaseType)
        {
            return typeof(NumericUpDown);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="attributes"></param>
        /// <returns></returns>
        public EventDescriptorCollection GetEvents(Attribute[] attributes)
        {
            return TypeDescriptor.GetEvents(this, attributes);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public EventDescriptorCollection GetEvents()
        {
            return TypeDescriptor.GetEvents(this);
        }

        public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
        {
            return TypeDescriptor.GetProperties(this);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public PropertyDescriptorCollection GetProperties()
        {
            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="pd"></param>
        /// <returns></returns>
        public object GetPropertyOwner(PropertyDescriptor pd)
        {
            return this;
        }

        #endregion
    }
}
